<?php
/**
 * 框架流程控制器，实现了统一入口的约定和访问流程调度
 * 
 * 流程约束:
 * 		约束了请求的标准格式。如果不合法的请求将抛出异常
 * 		/pevent.html?query=
 * 		/pevent/paction.html?query=
 * 		/open/pevent/paction.html?query=
 * 调度:
 * 		根据URL,包含插件的代码，控制访问插件流程。
 * 控制输出:
 * 		系统提供了两种的执行模式（CLI，CGI），三种的响应方式（html，ajax，iframe）。根据不同的请求会给与不同的响应输出
 * 流程常量:
 * 		根据请求，将会产生在插件中经常需要获取的常量定义N_EVENT,N_ACTION,N_TYPE,N_METHOD
 * 
 * @author 991<ruiyanlin@sohu-inc.com>
 * 
 */


class Controller extends Base{


	/**
	 * 控制器是整个流程的入口，可以在构造函数中增加初始化机制
	 * 默认将初始化控制器。为后续的系统调度提供了环境。
	 * 
	 * @param 		null
	 * @return 		null
	 */	
	public function __construct() {
		$this->init();
		//$this->run();

	}
	
	/**
	 * 控制器析构函数时一次请求中最后的处理。我们可以做一些请求结束后的回调业务。
	 * 
	 * html:
	 * 		一般请求，未有特殊处理。
	 * ajax:
	 * 		如果请求时ajax，那么系统将捕获输出缓存，并构造一个JSONP响应格式，响应格式[state,method,msg]
	 * iframe:
	 * 		如果请求是ifram,系统将构造最简单的html。如果返回结构中带有js，并且需要对页面进行操作。
	 * 
	 */
	public function __destruct(){
		
		//只有ajax,ifram才需要捕获输出缓存。
		if(in_array(N_TYPE,array('ajax','iframe'))){
		
			// ob_start();
			$msg = ob_get_contents();
			ob_end_clean();
						
			if('ajax'==N_TYPE){
				$rs = $_GET['cb'].'('.json_encode(array('state'=>true,'method'=>N_METHOD,'msg'=>$msg)).')';
			}elseif('iframe'==N_TYPE){
				$rs = "<html><head></head><body><script>";
				$rs .= "parent.ui.data=".json_encode(array('state'=>true,'method'=>N_METHOD,'msg'=>$msg));
				$rs .= "</script></body></html>";
			}		
			echo $rs;
		}
	}
	
	
	/**
	 * 控制器初始化
	 * 识别请求和环境，为后续的访问流程提供前提。
	 * 
	 * 识别访问模式:
	 * 		根据PHP系统变量，识别请求的执行模式，不同的执行模式对于参数的处理会有不同
	 * 		CGI执行模式中，PHP自身已经提供了一系列很好的的参数机制
	 * 		CLI执行模式中，参数的个性化相对较弱，为了简化，系统就提供了一个参数。
	 * 流程常量:
	 * 		根据请求，生成流程常量，对于缺少的参数采用默认设置
	 * 
	 * @example 	$this->init();
	 * 
	 * @param 		null
	 * @return 		null
	 */
	private function init(){

		//解决cli和cgi的根目录定义
		if('Y'==N_CLI){
			
			//如果是cli请求模式，那么需要将命令行中的参数转化为系统全局变量
			global $argv;
			if(!isset($argv[1]) || !isset($argv[2])){
				throw new Exception("参数不正确");
			}
			$_GET['event'] = $argv[1];
			$_GET['action'] = $argv[2];
			if(isset($argv[3])){
				$_GET['data'] = $argv[3];
			}
		}


		//将请求作为常量定义
		//需要对请求数据请进行清理
		//请求都会先转为小写字母，然后首字母大写，并已Face结尾的文件。这遵循命名要求
		define('N_EVENT',strtolower(isset($_POST['event'])?$_POST['event']:(isset($_GET['event'])?$_GET['event']:N_DEFAULT_EVENT)));
		define('N_ACTION',strtolower(isset($_POST['action'])?$_POST['action']:(isset($_GET['action'])?$_GET['action']:N_DEFAULT_ACTION)));
		define('N_TYPE',strtolower(isset($_POST['type'])?$_POST['type']:(isset($_GET['type'])?$_GET['type']:N_DEFAULT_TYPE)));
		define('N_METHOD',strtolower(isset($_POST['method'])?$_POST['method']:(isset($_GET['method'])?$_GET['method']:N_DEFAULT_METHOD)));
		
		//如果请求为ajax或者ifram，那么需要对输出缓存做控制。输出用户需要的数据。
		if(in_array(N_TYPE,array('ajax','iframe'))){
			ob_start();
		}


	}
	
	/**
	 * 访问调度
	 * 根据请求，控制访问流程
	 *
	 */
	public function run() {
		

		//判断是cli还是cgi模式
		$uEvent = ucfirst(N_EVENT);
		$cEvent = $uEvent . ('Y'==N_ADMIN?'Admin':'Face');
		if ('cli' == N_SCRIPT)
		{
			$cEvent = $uEvent . 'Script';
		}
		$path = N_PLUGINS . '/' . N_EVENT . '/' . $cEvent . '.php';
		if(!file_exists($path)){
			throw new Exception('CORE:找不到插件.');
		}
		
		require_once $path;
		$eHandle = new $cEvent();
		$action = N_ACTION;
		/*
		if(!method_exists($eHandle, N_ACTION)){
			throw new CException('CORE:找不到动作.');
		}
		 * 
		 */
		$eHandle->$action();
		unset($eHandle);	//出发析构函数。如果直接 执行析构函数。对象并不会被释放
		
	}

}
